package com.walala.logic.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.walala.logic.cache.ClientCache;
import com.walala.logic.cache.ServerCache;
import com.walala.logic.protocol.ProtocolPackage;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * 连接到接入层的客户端
 * @author KayLi
 *
 */
public class ToGatewayClient {

	private Logger logger = LoggerFactory.getLogger(ToGatewayClient.class);
	
	private static ToGatewayClient instance = new ToGatewayClient();
	
	private ToGatewayClient() {}
	
	public static ToGatewayClient getInstance() {
		return instance;
	}
	
	/**
	 * 初始化到介入层的连接池
	 * @param address
	 * @param size
	 */
	public void initPool(String address,int size) {
		logger.info("init toGateway client connPool init,adress:[{}],size:[{}]");
		String[] split = address.split(":");
		if(split.length != 2) {
			logger.error("init toGateway client error,address is not avalidate,address:[{}]",address);
			return;
		}
		String ip = split[0];
		int port = Integer.valueOf(split[1]);
		if (size > 0) {
			for (int i = 0; i < size; i++) {
				EventLoopGroup group = null;
				Bootstrap b = null;
				try {
					group = new NioEventLoopGroup();
					b = new Bootstrap();
					b.group(group);
					b.channel(NioSocketChannel.class);
					b.option(ChannelOption.TCP_NODELAY, true);
					b.option(ChannelOption.SO_KEEPALIVE, true);
					b.option(ChannelOption.SO_RCVBUF, 1024000);
					b.option(ChannelOption.SO_SNDBUF, 1024000);
					b.option(ChannelOption.SO_TIMEOUT, 1000);
					b.handler(new ChannelInitializer<SocketChannel>() {
						@Override
						protected void initChannel(SocketChannel ch) throws Exception {
							ChannelPipeline pipeline = ch.pipeline();
							pipeline.addLast(new ClientDecoder());// 解码器
							pipeline.addLast(new ClientEncoder());// 编码器
							pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 3000));// 定时器,秒
							pipeline.addLast(new TogatewayHandler());
						}
					});
					ChannelFuture f = b.connect(ip, port).await();
					if (f.isSuccess()) {
						Channel channel = f.channel();
						logger.info("[initPool] channel id=[{}]", channel.id());
						ToGatewayConnection connection = new ToGatewayConnection(group, b, channel);
						ServerCache.setConnection(address, connection);
					} else {
						b = null;
						if (group != null) {
							group.shutdownGracefully();
							group = null;
						}
						logger.error("[initPool] can not connect;ip=[{}],port=[{}]",ip, port);
						//Global.GATEWAY_ADDRESS.remove(respKey);
						ServerCache.removeConnections(address);
						break;
					}
				} catch (Exception e) {
					logger.error("[initPool] cause is:", e);
					b = null;
					if (group != null) {
						group.shutdownGracefully();
						group = null;
					}
					//Global.GATEWAY_ADDRESS.remove(respKey);
				}
			}	
		}
	}

	/*public void send(String realIp, ProtocolPackage pack) {
		Channel channel = ClientCache.toGatewayChennel.get(realIp);
		if(channel == null || !channel.isActive() || !channel.isOpen()) {
			initChannel(realIp);
		}
		
	}*/

	/**
	 * 初始化到gateway的连接
	 * @param ip
	 * @param port
	 */
	public void init(String ip, int port) {
		EventLoopGroup group = null;
		Bootstrap b = null;
		try {
			group = new NioEventLoopGroup();
			b = new Bootstrap();
			b.group(group);
			b.channel(NioSocketChannel.class);
			b.option(ChannelOption.TCP_NODELAY, true);
			b.option(ChannelOption.SO_KEEPALIVE, true);
			b.option(ChannelOption.SO_RCVBUF, 1024000);
			b.option(ChannelOption.SO_SNDBUF, 1024000);
			b.option(ChannelOption.SO_TIMEOUT, 1000);
			b.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ChannelPipeline pipeline = ch.pipeline();
					pipeline.addLast(new ClientDecoder());// 解码器
					pipeline.addLast(new ClientEncoder());// 编码器
					pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 3000));// 定时器,秒
					pipeline.addLast(new TogatewayHandler());
				}
			});
			ChannelFuture f = b.connect(ip, port).await();
			if (f.isSuccess()) {
				Channel channel = f.channel();
				if(channel != null && channel.isActive()) {
					ClientCache.toGatewayChennel.put(ip + ":" + port, channel);
				}
			} else {
				b = null;
				if (group != null) {
					group.shutdownGracefully();
					group = null;
				}
				logger.error("[initPool] can not connect;ip=[{}],port=[{}]",ip, port);
				//Global.GATEWAY_ADDRESS.remove(respKey);
				ClientCache.toGatewayChennel.remove(ip + ":" + port);
			}
		} catch (Exception e) {
			logger.error("[init toGateway Channle] cause is:", e);
			b = null;
			if (group != null) {
				group.shutdownGracefully();
				group = null;
			}
			//Global.GATEWAY_ADDRESS.remove(respKey);
		}
		
	}

	public Channel getChannel(String ip, int port) {
		EventLoopGroup group = null;
		Bootstrap b = null;
		try {
			group = new NioEventLoopGroup();
			b = new Bootstrap();
			b.group(group);
			b.channel(NioSocketChannel.class);
			b.option(ChannelOption.TCP_NODELAY, true);
			b.option(ChannelOption.SO_KEEPALIVE, true);
			b.option(ChannelOption.SO_RCVBUF, 1024000);
			b.option(ChannelOption.SO_SNDBUF, 1024000);
			b.option(ChannelOption.SO_TIMEOUT, 1000);
			b.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ChannelPipeline pipeline = ch.pipeline();
					pipeline.addLast(new ClientDecoder());// 解码器
					pipeline.addLast(new ClientEncoder());// 编码器
					pipeline.addLast("idleStateHandler", new IdleStateHandler(0, 0, 3000));// 定时器,秒
					pipeline.addLast(new TogatewayHandler());
				}
			});
			ChannelFuture f = b.connect(ip, port).await();
			if (f.isSuccess()) {
				Channel channel = f.channel();
				if(channel != null && channel.isActive()) {
					ClientCache.toGatewayChennel.put(ip + ":" + port, channel);
					return channel;
				}
			} else {
				b = null;
				if (group != null) {
					group.shutdownGracefully();
					group = null;
				}
				logger.error("[initPool] can not connect;ip=[{}],port=[{}]",ip, port);
				//Global.GATEWAY_ADDRESS.remove(respKey);
				ClientCache.toGatewayChennel.remove(ip + ":" + port);
			}
		} catch (Exception e) {
			logger.error("[init toGateway Channle] cause is:", e);
			b = null;
			if (group != null) {
				group.shutdownGracefully();
				group = null;
			}
		}
		return null;
	}
	
}
